package com.vcaresolution.logistic.util;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;

import com.vcaresolution.logistic.controller.BaseController;
import com.vcaresolution.logistic.to.BusinessProcessTO;
import com.vcaresolution.util.Utils;

public class WebServiceScheduler extends BaseController implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	public final static String DAILY = "Daily";
	public final static String WEEKLY = "Weekly";
	public final static String MONTHLY = "Monthly";
	public final static String PROPERTY_SEPARATOR = ";";
	public final static String[] DAYS_NAME = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
	
	/**
	 * This method responsible for schedule WebServiceProcess which is related to ShipSoft Application.
	 * Method make jobTrigger and scheduleJob for particular WebServiceProcess which is configure in Database.
	 * 
	 * This method initated when Spring initialized this Bean.
	 */
	public void startWebServiceScehduler() {
		
		try {
			SchedulerFactory schedulerFactory = new StdSchedulerFactory();
			Scheduler scheduler = null;
			scheduler = schedulerFactory.getScheduler();
			scheduler.start();
			List<BusinessProcessTO> businessProcessList = getServiceRegistry().getExportService().getBusinessProcesses();
			
			if(businessProcessList != null && businessProcessList.size() > 0){
				
				Iterator<BusinessProcessTO> serviceIterator = businessProcessList.iterator();
				
				while (serviceIterator.hasNext()) {
					BusinessProcessTO businessProcessTO = serviceIterator.next();
					
					Trigger jobTrigger = null;
					JobDetail jobDetail = null;				
					JobDataMap map = new JobDataMap();
					map.put("processname", businessProcessTO.getProcessname());
					map.put("processid", businessProcessTO.getProcessid());
					map.put("properties", formatProperties(businessProcessTO.getProperty())); 
	
					if (businessProcessTO.getStartdatetime() != null) {
						String jobAndTriggerName = businessProcessTO.getProcessname()+ "_" + businessProcessTO.getProcessid();
	
						if(businessProcessTO.getDuration() != null && businessProcessTO.getDuration() > 0 ) {	
							
							jobDetail = new JobDetail(jobAndTriggerName+ "_JOB", Scheduler.DEFAULT_GROUP, 
														Class.forName(businessProcessTO.getClassname()));
							jobDetail.setJobDataMap(map);
							
							jobTrigger = TriggerUtils.makeSecondlyTrigger(Integer.parseInt(""+ businessProcessTO.getDuration()));
							jobTrigger.setStartTime(businessProcessTO.getStartdatetime());
							if ( businessProcessTO.getEnddatetime() != null )
								jobTrigger.setEndTime(businessProcessTO.getEnddatetime());
							jobTrigger.setName(jobAndTriggerName + "_TRIGGER");
							
							scheduler.scheduleJob(jobDetail, jobTrigger);
							
						} else {
							
							String scheduleTimes = businessProcessTO.getScheduletimes();
							if( (scheduleTimes != null && scheduleTimes.trim().length() > 0) && (businessProcessTO.getEnddatetime() == null 
									|| businessProcessTO.getEnddatetime().after(new java.util.Date()))) {
								
								String strScheduleTime = null;
								String timeTokenList[] = Utils.getTokens(scheduleTimes, ";", true);
								
								for(int i=0;i<timeTokenList.length;i++){
									
										strScheduleTime = timeTokenList[i];
										try{
											java.util.Calendar time = Utils.getTime(strScheduleTime);
											
											if(businessProcessTO.getScheduleruntype() != null && 
													businessProcessTO.getScheduleruntype().equalsIgnoreCase(WEEKLY)){
												
												jobTrigger = TriggerUtils.makeWeeklyTrigger(jobAndTriggerName + "_" + strScheduleTime + "_TRIGGER",
														businessProcessTO.getDayofweek(),    
														time.get(java.util.Calendar.HOUR_OF_DAY),
														time.get(java.util.Calendar.MINUTE));
												
											} else if (businessProcessTO.getScheduleruntype() != null && 
													businessProcessTO.getScheduleruntype().equalsIgnoreCase(MONTHLY)) {
												
												jobTrigger = TriggerUtils.makeMonthlyTrigger(jobAndTriggerName + "_" + strScheduleTime + "_TRIGGER", 
														businessProcessTO.getDayofmonth(), 
														time.get(java.util.Calendar.HOUR_OF_DAY), 
														time.get(java.util.Calendar.MINUTE));
											} else {
												
												jobTrigger = TriggerUtils.makeDailyTrigger(jobAndTriggerName +"_"+strScheduleTime+"_TRIGGER",
																	time.get(java.util.Calendar.HOUR_OF_DAY),time.get(java.util.Calendar.MINUTE));
												
											}
												
											jobTrigger.setMisfireInstruction(Trigger.INSTRUCTION_RE_EXECUTE_JOB);
											jobTrigger.setStartTime(new Date());
											
											if (businessProcessTO.getEnddatetime() != null) {
												jobTrigger.setEndTime(businessProcessTO.getEnddatetime());
											}
											
											jobTrigger.setName(jobAndTriggerName +"_"+strScheduleTime+"_TRIGGER_"+i);
											
											jobDetail = new JobDetail(jobAndTriggerName	+"_"+strScheduleTime+ "_JOB", Scheduler.DEFAULT_GROUP, 
															Class.forName(businessProcessTO.getClassname()));
											
											jobDetail.setJobDataMap(map);
											
											scheduler.scheduleJob(jobDetail, jobTrigger);
											
										} catch(Exception e) {
											e.printStackTrace();
										}
								}
							}
						}
	
					}
				}
		 }	
		}catch (SchedulerException e) {
			e.printStackTrace();
		} 
		catch(Exception exception){
			exception.printStackTrace();
		}
	}

	/**
	 * This method responsible to format Properties
	 * @param propertyString
	 * @return
	 */
	public static HashMap<String, String> formatProperties(String propertyString){
		HashMap<String, String> propertyMap = new HashMap<String, String>(); 
		if(propertyString == null || propertyString.trim().length() <= 0)
			return propertyMap;
		
		String[] properties = propertyString.split(PROPERTY_SEPARATOR);
		String[] keyValue = null;
		for(String property : properties)
		{
			keyValue = property.split("=");
			if(keyValue != null && keyValue.length > 1)
				propertyMap.put(keyValue[0], keyValue[1]);
		}
		return propertyMap;
	}
}
